﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using CS_ServerDLL;
using CS_Util;

/// <summary>
/// 传奇PC版本修改工具
/// </summary>
namespace build {
    internal class Program {
        //修改exe的dll的名字
        const string changeExeIconDllName = @"ChangeExeIcon.dll";

        //默认渠道号
        const string defaultChannelCode = "CCCCTJXY";
        //默认开启输入渠道号
        const string defaultCanInputChannel = "0";
        //默认关闭测试
        const string defaultOpenTest = "1";
        //工程路径名
        const string exeFloder = @"app";
        //默认应用名配置文件路径
        const string defaultAppnameConfigPath = @"StartTools\DefaultgameName.txt";
        //是否已经找到窗体
        static bool hasFindWindow = false;
        static C_Console c_Console;
        static void Main() {
            S_Build();
        }
        static void S_Build() { 
            string currPath = AppDomain.CurrentDomain.BaseDirectory;//正式
            //string fileDir = @"C:\Users\wangdoudou\Desktop\Build_Win32\";//测试  
            c_Console = new C_Console().S_Init("logList", currPath);


            DirectoryInfo[] dics = new DirectoryInfo(currPath).GetDirectories();
            for (int i3 = 0; i3 < dics.Length; i3++) {
                string configDir = dics[i3].FullName + "/";

                C_Log.Log("############################################################当前程序文件夹：" + configDir);
                C_Log.Log("//工具配置文件路径");
                C_Log.Log("//要替换为的图标路径");

                C_Log.Log("//读取工具配置文件");
                //string tempNamePath = currPath + defaultAppnameConfigPath;   
                build_config configData = new build_config();
                if (configData.S_LoadData(configDir) == false) {
                    C_Log.LogError("未找到配置文件路径....无法打包....." + configData.o_configPath);
                    continue;
                }

                C_Log.Log("//移动 exeFloder 到 releaseAppFloder");
                string sourceExePath = currPath + exeFloder;
                string saveExePath = string.Format(@"{0}_build\{1}\", currPath, dics[i3].Name);
                DeleateFile(saveExePath);
                CopyDirectory(sourceExePath, saveExePath);
                DeleateFile(saveExePath + "Cache");
                string dataFile = string.Format(@"{0}{1}_Data", saveExePath, build_config.defGameName);
                string renameDataFile = string.Format(@"{0}{1}_Data", saveExePath, configData.o_gameName);
                string exeFile = saveExePath + build_config.defGameName + ".exe";
                string renameExeFile = saveExePath + configData.o_gameName + ".exe";
                ChangeFileName(exeFile, renameExeFile);
                ChangeFloderName(dataFile, renameDataFile);


                string StreamingAssets = string.Format(@"{0}\StreamingAssets\", renameDataFile);
                string projectConfigPath = StreamingAssets + "config.txt";

                if (File.Exists(projectConfigPath)) {
                    C_Log.Log("//加载并修改项目配置....." + projectConfigPath);
                    build_config.S_FixConfig(projectConfigPath, configData);
                } else {
                    C_Log.LogError("未找到项目配置文件路径....." + projectConfigPath);
                    S_Exit_Pause();
                    continue;
                }
                CopyDirectory(configDir + @"assets\", StreamingAssets);


                string icoFile = configDir + "icon.ico";

                S_genIco2(configDir + "icon.png", icoFile);

                if (File.Exists(renameExeFile) == false) {
                    C_Log.LogError("未找到项目运行文件路径......" + renameExeFile);
                    S_Exit_Pause();
                    continue;
                }
                if (File.Exists(icoFile)) {
                    if (ChangeExeIcon(renameExeFile, icoFile)) {
                        C_Log.LogFormat("ico替换成功!.....{0}....{1}", renameExeFile, icoFile);
                    } else {
                        C_Log.LogErrorFormat("替换失败.....{0}....{1}", renameExeFile, icoFile);
                        S_Exit_Pause();
                        continue;
                    }
                } else {
                    C_Log.LogErrorFormat("ico文件不存在....{0}....{1}", renameExeFile, icoFile);
                }
                string dllName = renameExeFile.Replace("exe", "dll");
                ChangeFileName(renameExeFile, dllName);

                CopyDirectory(currPath + @"StartTools\", saveExePath);
                ChangeFileName(saveExePath + "StartAPP.exe", renameExeFile);

                if (File.Exists(icoFile)) {
                    C_Log.LogFormat("替换exe的图标222.....{0}....{1}", renameExeFile, icoFile);
                    if (ChangeExeIcon(renameExeFile, icoFile)) {
                        C_Log.LogFormat("ico替换成功222.......{0}....{1}", renameExeFile, icoFile);
                    } else {
                        C_Log.LogErrorFormat("ico替换失败222...{0}....{1}", renameExeFile, icoFile);
                        S_Exit_Pause();
                        continue;
                    }
                }

                //if (MessageBox(IntPtr.Zero, "生成成功！", "提示", 0) != 0) {
                //    C_Log.Log("生成完成");
                //}

                if (configData.openTest != null && configData.openTest.Equals("0", StringComparison.OrdinalIgnoreCase)) {
                    // C_Log.Log("//运行exe");
                    //System.Diagnostics.Process.Start(renameExeFile);

                    ///.Log("//运行dll");
                    STARTUPINFO sInfo = new STARTUPINFO();
                    PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();

                    if (!CreateProcess(new StringBuilder(dllName), new StringBuilder(dllName), null, null, false, 0, null, null, ref sInfo, ref pInfo)) {
                        C_Log.LogError("创建运行dll进程失败");
                        S_Exit_Pause();
                        continue;
                    } else {
                        C_Log.Log("创建运行dll进程成功");
                    }
                    uint u = 0;
                    WaitForSingleObject(pInfo.hProcess, int.MaxValue);
                    GetExitCodeProcess(pInfo.hProcess, ref u);
                    CloseHandle(pInfo.hProcess);
                    CloseHandle(pInfo.hThread);

                    C_Log.Log("//修改窗体名称");
                    while (!hasFindWindow) {
                        ChangeWindowTitle(build_config.defGameName, configData.o_gameName);
                    }
                }
            }
            S_Exit_Pause();
        }

        static void S_test02() {
            string pp1 = @"D:\app2build\com.xinyu.juliang_210926_1617\icon.png";
            string pp2 = @"D:\app2build\com.xinyu.juliang_210926_1617\icon.ico";
            S_genIco2(pp1, pp2);
        }

        static void S_Exit_Pause() {
            C_LogTxtSave.S_SaveData();
            C_Log.Log("完成...");
            C_Log.Log("完成...");
            C_Log.Log("完成...");
            C_Log.Log("完成...");
            //while (true) {
            //    Console.ReadKey();
            //}
        }

        /// <summary>
        /// 加载默认应用名
        /// </summary>
        /// <param name="filePath">路径</param>
        /// <returns></returns>
        public static string LoadDefaultGameName(string filePath) {
            string tempName = "";

            string[] lines = File.ReadAllLines(filePath, Encoding.UTF8);
            if (lines == null || lines.Length == 0) {
                return tempName;
            }

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < lines.Length; i++) {
                string line = lines[i].Trim();
                if (string.IsNullOrEmpty(line) || line.StartsWith("#", StringComparison.OrdinalIgnoreCase)) {
                    continue;
                }

                if (line.Contains("=")) {
                    string[] arr = line.Split('=');
                    if (arr == null || arr.Length == 0) {
                        continue;
                    }

                    if (arr[0].Equals("DefaultgameName", StringComparison.OrdinalIgnoreCase)) {
                        if (arr.Length == 2) {
                            tempName = arr[1];
                            break;
                        }
                    }
                }
            }

            return tempName;
        }
        /// <summary>
        /// 修改窗体标题名称
        /// </summary>
        /// <param name="titleName">原窗体名称</param>
        /// <param name="changeName">要修改为的窗体名称</param>
        public static void ChangeWindowTitle(string titleName, string changeName) {
            if (string.IsNullOrEmpty(titleName)) {
                return;
            }

            //查找窗体
            int intPtr = FindWindowByName(null, titleName);

            //窗体存在
            if (intPtr != 0) {
                hasFindWindow = true;
                C_Log.Log("窗体已找到!");
                if (SetWindowText(intPtr, changeName) != 0) {
                    C_Log.Log("设置标题成功!");
                } else {
                    C_Log.LogError("设置标题失败!");
                }
            }
        }

        /// <summary>
        /// 重命名文件
        /// </summary>
        /// <param name="exeName">原始exe名称</param>
        /// <param name="renameExeName">要修改为的exe名称</param>
        /// <param name="dataFloderName">原始文件夹名称</param>
        /// <param name="renameDataFloderName">要修改为的文件夹名称</param>
        public static void ChangeFileName(string exeName, string renameExeName) {
            C_Log.LogFormat("修改名字......{0}....{1}", exeName, renameExeName);
            if (string.IsNullOrEmpty(exeName) || string.IsNullOrEmpty(renameExeName)) {
                return;
            }

            if (!File.Exists(exeName)) {
                return;
            }

            File.Move(exeName, renameExeName);
        }

        /// <summary>
        /// 重命名文件夹
        /// </summary>
        /// <param name="dataFloderName">原始文件夹名称</param>
        /// <param name="renameDataFloderName">要修改为的文件夹名称</param>
        public static void ChangeFloderName(string dataFloderName, string renameDataFloderName) {
            C_Log.LogFormat("重命名文件夹......{0}....{1}", dataFloderName, renameDataFloderName);
            if (string.IsNullOrEmpty(dataFloderName) || string.IsNullOrEmpty(renameDataFloderName)) {
                return;
            }

            if (!Directory.Exists(dataFloderName)) {
                return;
            }

            Directory.Move(dataFloderName, renameDataFloderName);
        }
        /// <summary>
        /// 拷贝文件夹到指定目录
        /// </summary>
        /// <param name="sourceDirPath">原始文件夹</param>
        /// <param name="SaveDirPath">要保存到的文件夹</param>
        public static void CopyDirectory(string sourceDirPath, string SaveDirPath) {
            C_Log.LogFormat("拷贝Dir.....{0}...{1}", sourceDirPath, SaveDirPath);
            try {
                //如果指定的存储路径不存在，则创建该存储路径
                if (!Directory.Exists(SaveDirPath)) {
                    //创建
                    Directory.CreateDirectory(SaveDirPath);
                }
                //获取源路径文件的名称
                string[] files = Directory.GetFiles(sourceDirPath);
                //遍历子文件夹的所有文件
                foreach (string file in files) {
                    string pFilePath = SaveDirPath + "\\" + Path.GetFileName(file);
                    if (File.Exists(pFilePath))
                        continue;
                    File.Copy(file, pFilePath, true);
                }
                string[] dirs = Directory.GetDirectories(sourceDirPath);
                //递归，遍历文件夹
                foreach (string dir in dirs) {
                    CopyDirectory(dir, SaveDirPath + "\\" + Path.GetFileName(dir));
                }
            } catch (Exception ex) {
                C_Log.LogErrorInfo("错误", ex);
            }
        }

        /// <summary>
        /// 拷贝单个文件到指定目录
        /// </summary>
        /// <param name="sourceDirPath">原始文件夹</param>
        /// <param name="SaveDirPath">要保存到的文件夹</param>
        public static void CopyFile(string filePath, string SaveDirPath, bool isCreateSaveDir = false) {
            try {
                if (!File.Exists(filePath)) {
                    return;
                }

                //如果指定的存储路径不存在，则创建该存储路径
                if (!Directory.Exists(SaveDirPath)) {
                    if (isCreateSaveDir) {
                        //创建
                        Directory.CreateDirectory(SaveDirPath);
                    } else {
                        return;
                    }
                }

                File.Copy(filePath, SaveDirPath + Path.GetFileName(filePath), true);
            } catch (Exception ex) {
                C_Log.LogErrorInfo("错误", ex);
            }
        }

        /// <summary>
        /// 删除文件夹下所有文件
        /// </summary>
        /// <param name="path"></param>
        public static void DeleateFile(string path) {
            if (string.IsNullOrEmpty(path)) {
                return;
            }

            if (!Directory.Exists(path)) {
                return;
            }

            try {
                string[] dirs = Directory.GetDirectories(path);
                if (dirs != null && dirs.Length > 0) {
                    for (int i = 0; i < dirs.Length; i++) {
                        Directory.Delete(dirs[i], true);
                    }
                }

                DirectoryInfo directoryInfo = new DirectoryInfo(path);
                FileInfo[] fileInfos = directoryInfo.GetFiles("*", SearchOption.AllDirectories);

                if (fileInfos != null && fileInfos.Length > 0) {
                    for (int i = 0; i < fileInfos.Length; i++) {
                        string filePath = path + "/" + fileInfos[i].Name;
                        File.Delete(filePath);
                    }
                }
            } catch (Exception ex) {
                C_Log.LogErrorInfo("错误", ex);
            }
        }     
        public static Icon S_genIco2(string sourcePath, string targetPath) {
            C_Log.LogFormat("生成iocn.....{0}...{1}", sourcePath, targetPath);
            Bitmap bmp = new Bitmap(sourcePath);  
            Icon icon = _genIco2(bmp); //通过句柄得到图标
            using (Stream stream = new System.IO.FileStream(targetPath, System.IO.FileMode.Create)) {
                icon.Save(stream);
            }
            return icon;
        }
        /// <summary>
        /// 转换Image为Icon
        /// </summary>
        /// <param name="image">要转换为图标的Image对象</param>
        /// <param name="nullTonull">当image为null时是否返回null。false则抛空引用异常</param>
        /// <exception cref="ArgumentNullException" />
        public static Icon _genIco2(Image image, bool nullTonull = false) {
            if (image == null) {
                if (nullTonull) { return null; }
                throw new ArgumentNullException("image");
            }

            using (MemoryStream msImg = new MemoryStream(), msIco = new MemoryStream()) {
                image.Save(msImg, ImageFormat.Png);

                using (var bin = new BinaryWriter(msIco)) {
                    //写图标头部
                    bin.Write((short)0);      //0-1保留
                    bin.Write((short)1);      //2-3文件类型。1=图标, 2=光标
                    bin.Write((short)1);      //4-5图像数量（图标可以包含多个图像）

                    bin.Write((byte)image.Width); //6图标宽度
                    bin.Write((byte)image.Height); //7图标高度
                    bin.Write((byte)0);      //8颜色数（若像素位深>=8，填0。这是显然的，达到8bpp的颜色数最少是256，byte不够表示）
                    bin.Write((byte)0);      //9保留。必须为0
                    bin.Write((short)0);      //10-11调色板
                    bin.Write((short)32);     //12-13位深
                    bin.Write((int)msImg.Length); //14-17位图数据大小
                    bin.Write(22);         //18-21位图数据起始字节

                    //写图像数据
                    bin.Write(msImg.ToArray());

                    bin.Flush();
                    bin.Seek(0, SeekOrigin.Begin);
                    return new Icon(msIco);
                }
            }
        }


        /// <summary>
        /// 修改exe图标
        /// </summary>
        /// <param name="exePath">目标exe路径</param>
        /// <param name="icoPath">图标路径</param>
        /// <returns></returns>
        //[DllImport(@"C:\Users\wangdoudou\Desktop\TJAPPTools\ChangeExeIcon.dll", EntryPoint = "ChangeExeIcon", CharSet = CharSet.Unicode)]
        [DllImport(changeExeIconDllName, EntryPoint = "ChangeExeIcon", CharSet = CharSet.Unicode)]
        extern static bool ChangeExeIcon(string exePath, string icoPath);

        /// <summary>
        /// 查找窗体句柄
        /// </summary>
        /// <param name="lpClassName"></param>
        /// <param name="lpWindowName">窗体名字</param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Unicode)]
        extern static int FindWindowByName(string lpClassName, string lpWindowName);

        /// <summary>
        /// 设置窗体标题
        /// </summary>
        /// <param name="windowPtr">窗体句柄id</param>
        /// <param name="lpString">新标题名称</param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "SetWindowText", CharSet = CharSet.Unicode)]
        extern static int SetWindowText(int windowPtr, string lpString);

        /// <summary>
        /// 系统消息弹窗
        /// </summary>
        /// <param name="handle">窗体句柄</param>
        /// <param name="message">提示信息</param>
        /// <param name="title">提示标题</param>
        /// <param name="type">提示类型</param>
        /// <returns></returns>
        [DllImport("user32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Unicode)]
        public static extern int MessageBox(IntPtr handle, string message, string title, int type);


        [DllImport("Kernel32.dll ", EntryPoint = "CreateProcess", CharSet = CharSet.Unicode)]
        public static extern bool CreateProcess(
           StringBuilder lpApplicationName, StringBuilder lpCommandLine,
           SECURITY_ATTRIBUTES lpProcessAttributes,
           SECURITY_ATTRIBUTES lpThreadAttributes,
            bool bInheritHandles,
            int dwCreationFlags,
           StringBuilder lpEnvironment,
           StringBuilder lpCurrentDirectory,
            ref STARTUPINFO lpStartupInfo,
            ref PROCESS_INFORMATION lpProcessInformation
           );

        /// <summary>
        /// 检测一个系统核心对象(线程，事件，信号)的信号状态
        /// 当对象执行时间超过dwMilliseconds就返回，否则就一直等待对象返回信号
        /// </summary>
        /// <param name="hHandle"></param>
        /// <param name="dwMilliseconds"></param>
        /// <returns></returns>
        [DllImport("Kernel32.dll")]
        public static extern uint WaitForSingleObject(System.IntPtr hHandle, uint dwMilliseconds);

        /// <summary>
        /// 关闭一个内核对象,释放对象占有的系统资源。
        /// 其中包括文件、文件映射、进程、线程、安全和同步对象等
        /// </summary>
        /// <param name="hObject"></param>
        /// <returns></returns>
        [DllImport("Kernel32.dll")]
        public static extern bool CloseHandle(System.IntPtr hObject);

        /// <summary>
        /// 获取一个已中断进程的退出代码,非零表示成功，零表示失败。
        /// 参数hProcess，想获取退出代码的一个进程的句柄，参数lpExitCode，用于装载进程退出代码的一个长整数变量。
        /// </summary>
        /// <param name="hProcess"></param>
        /// <param name="lpExitCode"></param>
        /// <returns></returns>
        [DllImport("Kernel32.dll")]
        static extern bool GetExitCodeProcess(System.IntPtr hProcess, ref uint lpExitCode);

    }
}